/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.butnet.myframe.hql.query;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.type.Type;

/**
 * 分页查询工具
 * @author Administrator
 */
public class PageQuery implements Query {

    private Query query = null;
    private Query countQuery = null;
    private Pattern pattern = null;
    private Matcher mathcer = null;

    /**
     * 分页查询
     * @param session
     * @param queryString hql语句
     */
    public PageQuery(Session session, String queryString) {
        query = session.createQuery(queryString);
        countQuery = session.createQuery(getQueryCountString(query.getQueryString()));
    }

    public PageQuery(Session session, String queryString, int first, int pageSize) {
        query = session.createQuery(queryString);
        countQuery = session.createQuery(getQueryCountString(query.getQueryString()));
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
    }

    /**
     * 分页查询
     * @param session
     * @param q
     */
    public PageQuery(Session session, Query q) {
        query = q;
        countQuery = session.createQuery(getQueryCountString(query.getQueryString()));
    }

    public PageQuery(Session session, Query q, int first, int pageSize) {
        query = q;
        countQuery = session.createQuery(getQueryCountString(query.getQueryString()));
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
    }

    /**
     * 分页查询
     * @param session
     * @param q
     */
    public PageQuery(Session session, SQLQuery q) {
        query = q;
        countQuery = session.createSQLQuery(getQueryCountString(query.getQueryString()));
    }

    public PageQuery(Session session, SQLQuery q, int first, int pageSize) {
        query = q;
        countQuery = session.createSQLQuery(getQueryCountString(query.getQueryString()));
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
    }

    /**
     * 分页查询
     * @param session
     * @param queryString
     * @param isSql 是否是sql查询
     */
    public PageQuery(Session session, String queryString, boolean isSql) {
        if (!isSql) {
            query = session.createQuery(queryString);
            countQuery = session.createQuery(getQueryCountString(query.getQueryString()));
        } else {
            query = session.createSQLQuery(queryString);
            countQuery = session.createSQLQuery(getQueryCountString(query.getQueryString()));
        }
    }

    public PageQuery(Session session, String queryString, boolean isSql, int first, int pageSize) {
        if (!isSql) {
            query = session.createQuery(queryString);
            countQuery = session.createQuery(getQueryCountString(query.getQueryString()));
        } else {
            query = session.createSQLQuery(queryString);
            countQuery = session.createSQLQuery(getQueryCountString(query.getQueryString()));
        }
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
    }

    public PageQuery(Session session, String dataQuery, String countQuery){
        query = session.createQuery(dataQuery);
        this.countQuery = session.createQuery(countQuery);
    }
    public PageQuery(Session session, String dataQuery, String countQuery, int first, int pageSize){
        query = session.createQuery(dataQuery);
        this.countQuery = session.createQuery(countQuery);
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
    }

    public PageQuery(Session session, String dataQuery, String countQuery, boolean isSql, int first, int pageSize){
        if(!isSql){
            query = session.createQuery(dataQuery);
            this.countQuery = session.createQuery(countQuery);
        }else{
            query = session.createSQLQuery(dataQuery);
            this.countQuery = session.createSQLQuery(countQuery);
        }
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
    }

    /**
     * 查询记录条数
     * @return
     */
    @SuppressWarnings("unchecked")
	public int queryCount() {
        List l = countQuery.list();
        return l.size() > 0 ? (Integer) l.get(0) : 0;
    }

    /**
     * 设置分页信息
     * @param first
     * @param pageSize
     */
    public void setPageInfo(int first, int pageSize) {
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
    }

    /**
     * 取得查询次数的查询语句
     * @param queryString 查询语句
     * @return 返回查询次数的语句
     */
    public String getQueryCountString(String queryString) {
        queryString = queryString.trim();
        String temp = queryString.toLowerCase();
        String reStr = null;
        if (temp.startsWith("select")) {
            pattern = Pattern.compile("(\\s+from\\s+)");
            mathcer = pattern.matcher(temp);
            if (mathcer.find()) {
                int start = mathcer.start();
                pattern = Pattern.compile("(\\s+order\\s+by\\s+)");
                mathcer = pattern.matcher(temp);
                if (mathcer.find()) {
                    reStr = "select count(*) " + queryString.substring(start, mathcer.start());
                } else {
                    reStr = "select count(*) " + queryString.substring(start);
                }
            } else {
                pattern = Pattern.compile("(\\s+order\\s+by\\s+)");
                mathcer = pattern.matcher(temp);
                if (mathcer.find()) {
                    reStr = "select count(*) " + queryString.substring(0, mathcer.start());
                } else {
                    reStr = "select count(*) " + queryString;
                }
            }
        } else {
            pattern = Pattern.compile("(\\s+order\\s+by\\s+)");
            mathcer = pattern.matcher(temp);
            if (mathcer.find()) {
                reStr = "select count(*) " + queryString.substring(0, mathcer.start());
            } else {
                reStr = "select count(*) " + queryString;
            }
        }

        return reStr;
    }

    @Override
    public String getQueryString() {
        return query.getQueryString();
    }

    @Override
    public Type[] getReturnTypes() throws HibernateException {
        return query.getReturnTypes();
    }

    @Override
    public String[] getReturnAliases() throws HibernateException {
        return query.getReturnAliases();
    }

    @Override
    public String[] getNamedParameters() throws HibernateException {
        return query.getNamedParameters();
    }

    @SuppressWarnings("unchecked")
	@Override
    public Iterator iterate() throws HibernateException {
        return query.iterate();
    }

    @Override
    public ScrollableResults scroll() throws HibernateException {
        return query.scroll();
    }

    @Override
    public ScrollableResults scroll(ScrollMode arg0) throws HibernateException {
        return query.scroll(arg0);
    }

    @SuppressWarnings("unchecked")
	@Override
    public List list() throws HibernateException {
        return query.list();
    }

    @Override
    public Object uniqueResult() throws HibernateException {
        return query.uniqueResult();
    }

    @Override
    public int executeUpdate() throws HibernateException {
        return query.executeUpdate();
    }

    @Override
    public Query setMaxResults(int arg0) {
        return query.setMaxResults(arg0);
    }

    @Override
    public Query setFirstResult(int arg0) {
        return query.setFetchSize(arg0);
    }

    @Override
    public Query setReadOnly(boolean arg0) {
        return query.setReadOnly(arg0);
    }

    @Override
    public Query setCacheable(boolean arg0) {
        countQuery.setCacheable(arg0);
        return query.setCacheable(arg0);
    }

    @Override
    public Query setCacheRegion(String arg0) {
        countQuery.setCacheRegion(arg0);
        return query.setCacheRegion(arg0);
    }

    @Override
    public Query setTimeout(int arg0) {
        countQuery.setTimeout(arg0);
        return query.setTimeout(arg0);
    }

    @Override
    public Query setFetchSize(int arg0) {
        return query.setFetchSize(arg0);
    }

    @Override
    public Query setLockMode(String arg0, LockMode arg1) {
        return query.setLockMode(arg0, arg1);
    }

    @Override
    public Query setComment(String arg0) {
        return query.setComment(arg0);
    }

    @Override
    public Query setFlushMode(FlushMode arg0) {
        countQuery.setFlushMode(arg0);
        return query.setFlushMode(arg0);
    }

    @Override
    public Query setCacheMode(CacheMode arg0) {
        countQuery.setCacheMode(arg0);
        return query.setCacheMode(arg0);
    }

    @Override
    public Query setParameter(int arg0, Object arg1, Type arg2) {
        countQuery.setParameter(arg0, arg1, arg2);
        return query.setParameter(arg0, arg1, arg2);
    }

    @Override
    public Query setParameter(String arg0, Object arg1, Type arg2) {
        countQuery.setParameter(arg0, arg1, arg2);
        return query.setParameter(arg0, arg1, arg2);
    }

    @Override
    public Query setParameter(int arg0, Object arg1) throws HibernateException {
        countQuery.setParameter(arg0, arg1);
        return query.setParameter(arg0, arg1);
    }

    @Override
    public Query setParameter(String arg0, Object arg1) throws HibernateException {
        countQuery.setParameter(arg0, arg1);
        return query.setParameter(arg0, arg1);
    }

    @Override
    public Query setParameters(Object[] arg0, Type[] arg1) throws HibernateException {
        countQuery.setParameters(arg0, arg1);
        return query.setParameters(arg0, arg1);
    }

    @SuppressWarnings("unchecked")
	@Override
    public Query setParameterList(String arg0, Collection arg1, Type arg2) throws HibernateException {
        countQuery.setParameterList(arg0, arg1, arg2);
        return query.setParameterList(arg0, arg1, arg2);
    }

    @SuppressWarnings("unchecked")
	@Override
    public Query setParameterList(String arg0, Collection arg1) throws HibernateException {
        countQuery.setParameterList(arg0, arg1);
        return query.setParameterList(arg0, arg1);
    }

    @Override
    public Query setParameterList(String arg0, Object[] arg1, Type arg2) throws HibernateException {
        countQuery.setParameterList(arg0, arg1, arg2);
        return query.setParameterList(arg0, arg1, arg2);
    }

    @Override
    public Query setParameterList(String arg0, Object[] arg1) throws HibernateException {
        countQuery.setParameterList(arg0, arg1);
        return query.setParameterList(arg0, arg1);
    }

    @Override
    public Query setProperties(Object arg0) throws HibernateException {
        countQuery.setProperties(arg0);
        return query.setProperties(arg0);
    }

    @Override
    public Query setString(int arg0, String arg1) {
        countQuery.setString(arg1, arg1);
        return query.setString(arg1, arg1);
    }

    @Override
    public Query setCharacter(int arg0, char arg1) {
        countQuery.setCharacter(arg0, arg1);
        return query.setCharacter(arg0, arg1);
    }

    @Override
    public Query setBoolean(int arg0, boolean arg1) {
        countQuery.setBoolean(arg0, arg1);
        return query.setBoolean(arg0, arg1);
    }

    @Override
    public Query setByte(int arg0, byte arg1) {
        countQuery.setByte(arg0, arg1);
        return query.setByte(arg0, arg1);
    }

    @Override
    public Query setShort(int arg0, short arg1) {
        countQuery.setShort(arg0, arg1);
        return query.setShort(arg0, arg1);
    }

    @Override
    public Query setInteger(int arg0, int arg1) {
        countQuery.setInteger(arg0, arg1);
        return query.setInteger(arg0, arg1);
    }

    @Override
    public Query setLong(int arg0, long arg1) {
        countQuery.setLong(arg0, arg1);
        return query.setLong(arg0, arg1);
    }

    @Override
    public Query setFloat(int arg0, float arg1) {
        countQuery.setFloat(arg0, arg1);
        return query.setFloat(arg0, arg1);
    }

    @Override
    public Query setDouble(int arg0, double arg1) {
        countQuery.setDouble(arg0, arg1);
        return query.setDouble(arg0, arg1);
    }

    @Override
    public Query setBinary(int arg0, byte[] arg1) {
        countQuery.setBinary(arg0, arg1);
        return query.setBinary(arg0, arg1);
    }

    @Override
    public Query setText(int arg0, String arg1) {
        countQuery.setText(arg1, arg1);
        return query.setText(arg1, arg1);
    }

    @Override
    public Query setSerializable(int arg0, Serializable arg1) {
        countQuery.setSerializable(arg0, arg1);
        return query.setSerializable(arg0, arg1);
    }

    @Override
    public Query setLocale(int arg0, Locale arg1) {
        countQuery.setLocale(arg0, arg1);
        return query.setLocale(arg0, arg1);
    }

    @Override
    public Query setBigDecimal(int arg0, BigDecimal arg1) {
        countQuery.setBigDecimal(arg0, arg1);
        return query.setBigDecimal(arg0, arg1);
    }

    @Override
    public Query setBigInteger(int arg0, BigInteger arg1) {
        countQuery.setBigInteger(arg0, arg1);
        return query.setBigInteger(arg0, arg1);
    }

    @Override
    public Query setDate(int arg0, Date arg1) {
        countQuery.setDate(arg0, arg1);
        return query.setDate(arg0, arg1);
    }

    @Override
    public Query setTime(int arg0, Date arg1) {
        countQuery.setTime(arg0, arg1);
        return query.setTime(arg0, arg1);
    }

    @Override
    public Query setTimestamp(int arg0, Date arg1) {
        countQuery.setTimestamp(arg0, arg1);
        return query.setTimestamp(arg0, arg1);
    }

    @Override
    public Query setCalendar(int arg0, Calendar arg1) {
        countQuery.setCalendar(arg0, arg1);
        return query.setCalendar(arg0, arg1);
    }

    @Override
    public Query setCalendarDate(int arg0, Calendar arg1) {
        countQuery.setCalendarDate(arg0, arg1);
        return query.setCalendarDate(arg0, arg1);
    }

    @Override
    public Query setString(String arg0, String arg1) {
        countQuery.setString(arg0, arg1);
        return query.setString(arg0, arg1);
    }

    @Override
    public Query setCharacter(String arg0, char arg1) {
        countQuery.setCharacter(arg0, arg1);
        return query.setCharacter(arg0, arg1);
    }

    @Override
    public Query setBoolean(String arg0, boolean arg1) {
        countQuery.setBoolean(arg0, arg1);
        return query.setBoolean(arg0, arg1);
    }

    @Override
    public Query setByte(String arg0, byte arg1) {
        countQuery.setByte(arg0, arg1);
        return query.setByte(arg0, arg1);
    }

    @Override
    public Query setShort(String arg0, short arg1) {
        countQuery.setShort(arg0, arg1);
        return query.setShort(arg0, arg1);
    }

    @Override
    public Query setInteger(String arg0, int arg1) {
        countQuery.setInteger(arg0, arg1);
        return query.setInteger(arg0, arg1);
    }

    @Override
    public Query setLong(String arg0, long arg1) {
        countQuery.setLong(arg0, arg1);
        return query.setLong(arg0, arg1);
    }

    @Override
    public Query setFloat(String arg0, float arg1) {
        countQuery.setFloat(arg0, arg1);
        return query.setFloat(arg0, arg1);
    }

    @Override
    public Query setDouble(String arg0, double arg1) {
        countQuery.setDouble(arg0, arg1);
        return query.setDouble(arg0, arg1);
    }

    @Override
    public Query setBinary(String arg0, byte[] arg1) {
        countQuery.setBinary(arg0, arg1);
        return query.setBinary(arg0, arg1);
    }

    @Override
    public Query setText(String arg0, String arg1) {
        countQuery.setText(arg0, arg1);
        return query.setText(arg0, arg1);
    }

    @Override
    public Query setSerializable(String arg0, Serializable arg1) {
        countQuery.setSerializable(arg0, arg1);
        return query.setSerializable(arg0, arg1);
    }

    @Override
    public Query setLocale(String arg0, Locale arg1) {
        countQuery.setLocale(arg0, arg1);
        return query.setLocale(arg0, arg1);
    }

    @Override
    public Query setBigDecimal(String arg0, BigDecimal arg1) {
        countQuery.setBigDecimal(arg0, arg1);
        return query.setBigDecimal(arg0, arg1);
    }

    @Override
    public Query setBigInteger(String arg0, BigInteger arg1) {
        countQuery.setBigInteger(arg0, arg1);
        return query.setBigInteger(arg0, arg1);
    }

    @Override
    public Query setDate(String arg0, Date arg1) {
        countQuery.setDate(arg0, arg1);
        return query.setDate(arg0, arg1);
    }

    @Override
    public Query setTime(String arg0, Date arg1) {
        countQuery.setTime(arg0, arg1);
        return query.setTime(arg0, arg1);
    }

    @Override
    public Query setTimestamp(String arg0, Date arg1) {
        countQuery.setTimestamp(arg0, arg1);
        return query.setTimestamp(arg0, arg1);
    }

    @Override
    public Query setCalendar(String arg0, Calendar arg1) {
        countQuery.setCalendar(arg0, arg1);
        return query.setCalendar(arg0, arg1);
    }

    @Override
    public Query setCalendarDate(String arg0, Calendar arg1) {
        countQuery.setCalendarDate(arg0, arg1);
        return query.setCalendarDate(arg0, arg1);
    }

    @Override
    public Query setEntity(int arg0, Object arg1) {
        countQuery.setEntity(arg0, arg1);
        return query.setEntity(arg0, arg1);
    }

    @Override
    public Query setEntity(String arg0, Object arg1) {
        countQuery.setEntity(arg0, arg1);
        return query.setEntity(arg0, arg1);
    }
}